// -*-mode:c++; coding:utf-8-*-

template<typename T,
	 std::size_t slot_number>
class basic_message_queue
{
public:
	typedef std::size_t size_type;
	typedef T value_type;

	enum { CAPACITY = slot_number };

public:
	basic_message_queue() 
		: m_head(0)
		, m_tail(0) {}

	size_type capacity() const {
		return CAPACITY;
	}

	bool push_back(const value_type &message) {
		const bool is_not_full = (! full());
		if(is_not_full)
		{
			// push back
			m_storage[m_tail] = message;
			m_tail = forward_positon(m_tail);
		}
		return is_not_full;
	}

	bool pop_front(value_type &message) {
		const bool is_not_empty = (! empty());
		if(is_not_empty)
		{
			message = m_storage[m_head];
			m_head = forward_positon(m_head);
		}
		return is_not_empty;
	}

	// push/pop for circular queue, alway push into back and pop
	// from front

	bool push(const value_type &message) {
		return push_back(message);
	}

	bool pop(value_type &message) {
		return pop_front(message);
	}

	bool full() const {
		return size() == (CAPACITY - 1);
	}
	
	bool empty() const {
		return m_head == m_tail;
	}

	size_type size() const {
		return (CAPACITY - m_head + m_tail) % CAPACITY;
	}

	void clear() {
		m_head = 0;
		m_tail = 0;
	}

	// helper for access/push/pop into circular queue
	//
	// m_tail is pointed to index[last element] + 1
	// m_head is pointed to index[first element]

	const value_type &back() const {
		return m_storage[backward_positon(m_tail)];
	}

	value_type &back() {
		return m_storage[backward_positon(m_tail)];
	}

	const value_type & front() const {
		return m_storage[m_head];
	}

	value_type & front() {
		return m_storage[m_head];
	}

protected:
	// helper for manipulate position of circular queue
	inline
	size_type forward_positon(const size_type &position) const {
		return (position + 1) % CAPACITY;
	}

	inline
	size_type backward_positon(const size_type &position) const {
		return (CAPACITY + position - 1) % CAPACITY;
	}
private:
	value_type m_storage[CAPACITY];

	size_type m_head;
	size_type m_tail;
};


// 非对称消息队列，即一个读多个写、或一个写多个读的情况
enum asymmetric_queue_condition
{
	c_one = 1,
	c_multiply
};

template<asymmetric_queue_condition which>
struct asymmetric_queue_traits
{
	typedef boost::mutex mutex;
	typedef boost::mutex::scoped_lock scoped_lock;
};

template<>
struct asymmetric_queue_traits<c_one>
{
private:
	struct null_mutex
	{
		struct scoped_lock 
		{
			scoped_lock(null_mutex &mutex) {}
		};
	};

public:
	typedef null_mutex mutex;
	typedef null_mutex::scoped_lock scoped_lock;
};

// front/m_head属于读者管理，back/m_tail属于写者管理
// 对于两者都要加锁的时候，统一先加写者锁、再加读者锁
template<typename Queue,
	 asymmetric_queue_condition Reader,
	 asymmetric_queue_condition Writer>
class asymmetric_message_queue
{
public:
	typedef Queue impl_type;
	typedef typename Queue::size_type size_type;
	typedef typename Queue::value_type value_type;

	typedef asymmetric_queue_traits<Reader> reader_traits;
	typedef asymmetric_queue_traits<Writer> writer_traits;

public:
	asymmetric_message_queue() {}

	size_type capacity() const {
		m_queue.capacity();
	}

	bool push_back(const value_type &message) {
		writer_traits::scoped_lock lock(m_writer_mutex);
		while(m_queue.full())
		{
			m_writer_condition.wait(m_writer_mutex);
		}
		const bool ok = m_queue.push_back(message);
		if(ok)
		{
			m_reader_condition.notify_one();
		}
		return ok;
	}

	bool pop_front(value_type &message) {
		reader_traits::scoped_lock lock(m_reader_mutex);
		const bool ok = m_queue.pop_front(message);
		if(ok)
		{
			m_writer_condition.notify_one();
		}
		return ok;
	}

	bool push(const value_type &message) {
		return push_back();
	}

	bool pop(value_type &message) {
		return pop_front(message);
	}

	bool full() const {
		writer_traits::scoped_lock lock(m_writer_mutex);
		reader_traits::scoped_lock lock(m_reader_mutex);
		return m_queue.full();
	}

	bool empty() const {
		writer_traits::scoped_lock lock(m_writer_mutex);
		reader_traits::scoped_lock lock(m_reader_mutex);
		return m_queue.empty();
	}

	size_type size() const {
		writer_traits::scoped_lock lock(m_writer_mutex);
		reader_traits::scoped_lock lock(m_reader_mutex);
		return m_queue.size();
	}

	void clear() const {
		writer_traits::scoped_lock lock(m_writer_mutex);
		reader_traits::scoped_lock lock(m_reader_mutex);
		m_queue.clear();
	}

	const value_type &back() const {
		writer_traits::scoped_lock lock(m_writer_mutex);
		return m_queue.back();
	}

	value_type &back() {
		writer_traits::scoped_lock lock(m_writer_mutex);
		return m_queue.back();
	}

	const value_type &front() const {
		reader_traits::scoped_lock lock(m_reader_mutex);
		return m_queue.front();
	}

	value_type &front() {
		reader_traits::scoped_lock lock(m_reader_mutex);
		return m_queue.front();
	}

private:
	Queue m_queue;

	reader_traits::mutex m_reader_mutex;
	reader_traits::condition m_reader_condition;

	writer_traits::mutex m_writer_mutex;
	writer_traits::condition m_writer_condition;
};
